// Main.cpp

// Implementacia Main.cpp

#include "Common/Main.h"
#include "Common/Protocol/CommandGen.h"
//#include "Common/Protocol/ServerSocket.h"
#include "Common/Protocol/Parser.h"
#include "Common/Interact.h"

#if defined(COACH)
#	include "Coach/CoachKernel.h"
#elif defined(GOALIE)
#	include "Player/GoalieTactics.h"
#else // !COACH && !GOALIE
#	include "Player/PlayerTactics.h"
#endif // COACH, GOALIE

#include "Support/Debug.h"
//#include <stdio.h>
//#include <string.h>

extern bool DribbleTesting;
extern bool PassTesting;
extern bool EvaluatingPanes;

	// Ohodnocovacia mapa
	CEvaluatingPanesMap* ePanesMap;

	// Zoznam informacii o hracoch, ktorych vidi hrac
	CEvaluatingPlayerList* ePlayerList;

// Element zretazeneho zoznamu, ktory uklada vzdy jeden modul
struct MODULE_ELEM
{
	Module* module;
	int task;
	int priority;
	
	MODULE_ELEM* next;
};

// Jedina instancia triedy Main
Main* Main::instance = NULL;


// Hlavny konstruktor
Main::Main() : Module("Main", "Hlavny modul", "v0.0.03")
{
	moduleList	= NULL;
	instance	= this;
	run			= true;
}

// Hlavny destruktor
Main::~Main()
{
	MODULE_ELEM* tmp;;

	while(moduleList)
	{
		tmp = moduleList->next;
		delete moduleList;
		moduleList = tmp;
	}
}

// Vrati interfejs pre dany vstupny parameter
Interface* Main::GetInterface(int nTask) const
{
	MODULE_ELEM* elem = moduleList;

	while(elem)
	{
		if(elem->task == nTask)
			return elem->module->GetInterface(nTask);
		elem = elem->next;
	}

	return NULL;
}

// Vrati modul pre dany vstupny parameter
Module* Main::GetModule(int nTask) const
{
	MODULE_ELEM* elem = moduleList;

	while (elem)
	{
		if (elem->task == nTask) 
			return elem->module;
		elem = elem->next;
	}

	return NULL;
}


// Inicializacia hlavneho modulu
// argc - pocet parametrov programu
// argv - parametre programu
// nTask - cislo ulohy
// vracia v pripade uspechu INIT_OK, INIT_ERR v pripade chyby

int Main::Init(int argc, char** argv, int nTask)
{
	MODULE_ELEM* elem = moduleList;
	int i, j, k;

	// Parametre neuronovych sieti
	DribbleTesting	= false;
	PassTesting		= false;
	for(i = 1; i < argc; i++)
	{
		if(strcmp(argv[i], "-dt") == 0)			// Siet pre driblovanie
		{
			DribbleTesting = true;
		} 
		else if(strcmp(argv[i], "-pt") == 0)	// Siet pre prihravky ("passable friend")
		{
			PassTesting = true;
			printf("Mame pass siet\n");			

		}
	}

	#if defined(COACH)
	#else

	// Parametre ohodnocovacej mapy
	//	EvaluatingPanes	= false;
	
	for(i = 1; i < argc; i++)
	{
		if(strcmp(argv[i], "-ep") == 0)			// Ohodnocovanie policok
		{
			double lfPaneSize;
			sscanf(argv[++i], "%lf", &lfPaneSize);
			printf("\nOhodnocovanie policok bolo aktivovane!\nVelkost policka bola zvolena %.3lf m\n\n", lfPaneSize);
		
			ePanesMap = new CEvaluatingPanesMap(lfPaneSize);
			ePlayerList = new CEvaluatingPlayerList(ePanesMap);

			EvaluatingPanes = true;

			break;
		} 
		
	}
	#endif
	
	// Ostatne parametre
	for(i = 1; i < argc; i++)
	{
		if(strcmp(argv[i], "-h") == 0)
		{
			fprintf(stderr, "\n%s %s prepinace:\n\n", (char*) GetName(), (char*) GetVersion());
			fprintf(stderr, "\t-h: tento help\n");
			fprintf(stderr, "\t-t <uloha>: prepne na ulohu\n\n");

			return INIT_ERR;
		}
		else if(strcmp(argv[i], "-t") == 0)
			break;
	}

	while(elem)
	{
		for(j = i; j < argc; j++)
		{
			if(strcmp(argv[j], "-t") == 0)
			{
				sscanf(argv[++j], "%d", &nTask);
				if(nTask == elem->task)
					break;
			}
		}

		for(k = j; k < argc; k++)
		{
			if(strcmp(argv[j], "-t") == 0)
				break;
		}
		
		fprintf(stderr, "Inicializacia: %s %s\n",
			(char*) elem->module->GetName(),
			(char*) elem->module->GetVersion());
		
		if(elem->module->Init(k - j, &argv[j], elem->task))
			return INIT_ERR;
		
		elem = elem->next;
	}

	return INIT_OK;
}

// Spustenie hlavneho modulu
void Main::Run(int)
{
	while(run)
	{
		MODULE_ELEM* elem = moduleList;
		while(elem != NULL)
		{
      try
      {
			  elem->module->Run(elem->task);
      } catch (...) {}
			elem = elem->next;
		}
	}
}

// Zaregistruje novy modul
// module - pointer na modul
// nTask - cislo ulohy
// nPriority - priorita ulohy
// vracia vzdy 1
int Main::RegisterModule(Module* module, int nTask, int nPriority)
{
	MODULE_ELEM* elem = moduleList;

	fprintf(stderr, "Registrujem: Cislo ulohy - %d, Priorita ulohy - %d\n", nTask, nPriority);
	
	if(elem != NULL)
	{
		while((elem->task != nTask) && (elem->next != NULL))
		{
			elem = elem->next;
		}

		if(elem->task == nTask)
		{
			if (elem->priority >= nPriority) 
				return 0;
		}
		else
		{
			elem->next = new MODULE_ELEM;
			elem = elem->next;
			elem->next = NULL;
		}
	}
	else
	{
		moduleList = elem = new MODULE_ELEM;
		elem->next = NULL;
	}

	elem->module	= module;
	elem->task		= nTask;
	elem->priority	= nPriority;

	return 1;
}


bool DribbleTesting;
bool PassTesting;

bool EvaluatingPanes;


// Hlavna funkcia hraca
// argc - pocet parametrov programu
// argv - parametre programu
// vracia v pripade uspechu 0, inak nieco ine
int main(int argc, char** argv)
{
	DBG_INIT();

	// Tieto objekty su globalne
	Main* main					= new Main;
	ServerSocket* serverSocket	= new ServerSocket;
	CommandGen* commandGen		= new CommandGen;
	Parser* parser				= new Parser;
	Interact* interact			= new Interact;

#if defined(COACH)
	CoachKernel* tactics	= new CoachKernel;
#elif defined(GOALIE)
	GoalieTactics* tactics	= new GoalieTactics;

#else // !COACH && !GOALIE
	PlayerTactics* tactics	= new PlayerTactics;

//	ePlayerList = new CEvaluatingPlayerList(ePanesMap);

#endif // COACH, GOALIE

	// Start hraca/brankara/kouca
	if(main->Init(argc, argv))
		return 1;
	main->Run();

	// Vymazanie objektov
	delete tactics;
	delete interact;
	delete parser;
	delete commandGen;
	delete serverSocket;
	delete main;

	/*
	SKONTROLOVAT SPRAVNE ZMAZANIE TYCHTO OBJEKTOV!

	delete ePlayerList;
	delete ePanesMap;
	*/
	DBG_DONE();

	return 0;
}

